home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / Sample Code / RAMDisk 1.1 / Sources / RamINIT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-13  |  20.1 KB  |  776 lines  |  [TEXT/MPS ]

  1. #define __DebugVersion    1
  2. /*
  3. **    Apple Macintosh Developer Technical Support
  4. **
  5. **    RAMInit.c: An INIT which installs DRVR for RamDisk
  6. **
  7. **    by Gordon Sheridan and Jim Luther
  8. **  modified by Brian Bechtel
  9. **
  10. **    File:        RamINIT.c
  11. **
  12. **    Copyright © 1992-1994 Apple Computer, Inc.
  13. **    All rights reserved.
  14. **
  15. **    You may incorporate this sample code into your applications without
  16. **    restriction, though the sample code has been provided "AS IS" and the
  17. **    responsibility for its operation is 100% yours.  However, what you are
  18. **    not permitted to do is to redistribute the source as "DTS Sample Code"
  19. **    after having made changes. If you're going to re-distribute the source,
  20. **    we require that you make it clear in the source that the code was
  21. **    descended from Apple Sample Code, but that you've made changes.
  22. **
  23. **    Change History (most recent first):
  24. **
  25. **    Change History (most recent first):
  26. **
  27. **         <7>    06/10/94    BL°B    Explicitly set zone to system zone before
  28. **                                    getting the DRVR resource.  Symantec 7.0
  29. **                                    doesn't set the System attribute on the DRVR
  30. **                                    resource.  This can be hard to track down.
  31. **         <6>    05/19/94    BL°B    Modified debugger macros to avoid use of ANSI
  32. **                                     routines, and weird c-string dependencies.
  33. **         <5>    10/15/93    JML        Added code to resize unit table if needed.
  34. **         <4>    10/14/93    JML        Implement AddDebuggerLabels routine for MacsBug.
  35. **                                     Added Panic debug macros.
  36. **         <3>     6/29/93    gs        Change AddDriveToQueue to start with drive number 5.
  37. **         <2>     6/28/93    gs        Change _DebugVersion to __DebugVersion
  38. **         <1>     6/13/93    gs        Implement AddDebuggerLabels routine for TMON.
  39. **         <0>     4/17/92    gs        Clean up for Sample Code release.
  40. **/
  41.  
  42. #include "RamDisk.h"
  43.  
  44. #ifdef __DebugVersion
  45.     #include <string.h>
  46.     #include <TextUtils.h>
  47. #endif
  48.  
  49. /*****************************************************************************/
  50.  
  51. /*
  52. **    Prototypes
  53. */
  54.  
  55. pascal    void    ShowIcon7(short iconId, Boolean advance);
  56. pascal    short    AddMyDrive (long size,short driveRef);    /* returns drive number */
  57. pascal    OSErr    DRVRInstall (Handle,short);
  58. pascal    OSErr    DRVRRemove (short);
  59. pascal    OSErr    InstallGlue (Handle,short);
  60.  
  61. void    main (void);
  62. OSErr    InitializeGlobals (DrvrGlobals *driverGlobals);
  63. Ptr        GetUnitTableBase (void);
  64. void    SetUnitTableBase (Ptr newUnitTableBase);
  65. short    GetUnitEntryCount (void);
  66. void    SetUnitEntryCount (short newUnitEntryCount);
  67. OSErr    GrowUnitTable (void);
  68. short    GetUnusedDrvrRefNum (void);
  69. OSErr    GetDrvrRefNum (short *drvrRefNum);
  70. OSErr    DriverInstall (Handle drvrHandle, short drvrRefNum);
  71. void    DriverRemove (short drvrRefNum);
  72. OSErr    AddDriveToQueue (long size, short drvrRef, short *driveNum);
  73. OSErr    RemoveDrive (short driveNum, DrvQElPtr *drivePtr);
  74.  
  75. #ifdef    __DebugVersion
  76.     short        NumToolboxTraps (void);
  77.     TrapType    GetTrapType (short theTrap);
  78.     Boolean        TrapAvailable (short theTrap);
  79.     void        AddDebuggerLabels (DrvrGlobals driverGlobals);
  80. #endif    __DebugVersion
  81.  
  82. /*****************************************************************************/
  83.  
  84. /*
  85. **    main
  86. */
  87.  
  88. void    main (void)
  89. {
  90.     DrvrGlobals    driverGlobals;
  91.     short        csParam[11];
  92.     short        drvrRefNum = 0;
  93.     short        driveNum = 0;
  94.     DrvQElPtr    driveQElPtr;
  95.     OSErr        result;
  96.     DCtlHandle    dceHandle;
  97.     Handle        driverHandle = nil;
  98.     char        handleState;
  99.  
  100. #ifdef THINK_C
  101.     RememberA0();
  102.     SetUpA4();
  103. #endif
  104. #ifdef __MWERKS__
  105.     long oldA4=SetCurrentA4();
  106. #endif
  107.  
  108.     
  109.     Panic("\pStarting RAMDisk");
  110.     ShowIcon7(rLoadOKIcon,false);    /* show OK icon to indicate we're executing */
  111.     
  112.     result = InitializeGlobals(&driverGlobals);
  113.     if (result != noErr)
  114.     {
  115.         Panic("\pCould not initialize globals");
  116.         goto Done;
  117.     }
  118.  
  119.     driverGlobals.ramDisk = NewPtrSysClear(driverGlobals.ramSize);
  120.     if (driverGlobals.ramDisk == nil)
  121.     {
  122.         Panic("\pNewSysPtr = nil");
  123.         result = memFullErr;
  124.         goto Done;
  125.     }
  126.  
  127. #ifdef    __DebugVersion
  128.     AddDebuggerLabels(driverGlobals);
  129. #endif    __DebugVersion
  130.     
  131.     result = GetDrvrRefNum(&drvrRefNum);
  132.     if (result != noErr)
  133.     {
  134.         Panic("\pGetDrvrRefNum failed!");
  135.         goto Done;
  136.     }
  137.     
  138.     SetZone(SystemZone());            /* <7> */
  139.  
  140.     driverHandle = Get1NamedResource(kDRVRType, kDriverName);
  141.     result = ResError();
  142.     if (result != noErr)
  143.     {
  144.         Panic("\pGet1NamedResource failed!");
  145.         goto Done;
  146.     }
  147.     
  148.     HLock(driverHandle);
  149.     DetachResource(driverHandle);
  150.     result = ResError();
  151.     if (result != noErr)
  152.     {
  153.         Panic("\pDetachResource failed!");
  154.         goto Done;
  155.     }
  156.     
  157.     SetZone(ApplicZone());            /* <7> */
  158.  
  159.     result = DriverInstall(driverHandle, drvrRefNum);
  160.     if (result != noErr)
  161.     {
  162.         Panic("\pDriverInstall failed!");
  163.         goto Done;
  164.     }
  165.     
  166.     result = OpenDriver(kDriverName, &drvrRefNum);
  167.     if (result != noErr)
  168.     {
  169.         Panic("\pOpenDriver failed");
  170.         goto Done;
  171.     }
  172.     
  173.     /* put in drive queue */
  174.     result = AddDriveToQueue (driverGlobals.ramSize / 512, drvrRefNum, &driveNum);
  175.     if (result != noErr)
  176.     {
  177.         Panic("\pAddMyDrive returned negative driveNum!");
  178.         goto Done;
  179.     }
  180.     /* driveNum now = drive number */
  181.     
  182.     /*    Save driveNum in our globals so driver code can verify drive number in
  183.         Prime, Status and Control calls (if need be). The driver also checks 
  184.         driveNum in the driver globals for a non-zero value before accepting
  185.         regular prime, control and status calls. */
  186.     driverGlobals.driveNumber = driveNum;
  187.  
  188.     /* set drivers globals */
  189.     *(Ptr *)csParam = (Ptr)&driverGlobals;
  190.     result = Control(drvrRefNum, setGlobalsCC, (Ptr)csParam);
  191.     if (result != noErr)
  192.     {
  193.         Panic("\pControl returned err");
  194.         goto Done;
  195.     }
  196.     
  197.     /* check to see if it got them */
  198.     result = Status(drvrRefNum, getGlobalsSC, (Ptr)csParam);
  199.     if ((result != noErr) || (driverGlobals.ramSize != *(long *)csParam))
  200.     {
  201.         Panic("\pStatus returned err");
  202.         goto Done;
  203.     }
  204.             
  205.     /* zero & mount */
  206.     result = DIZero(driveNum, driverGlobals.volumeName);
  207.     if (result != noErr)
  208.     {
  209.         Panic("\pDIZero returned err");
  210.         goto Done;
  211.     }
  212.     
  213. Done:
  214.     if (result == noErr)
  215.         ShowIcon7(rLoadOKIcon,true);    /* draw OK icon and move pen */
  216.     else
  217.     {
  218.         dceHandle = GetDCtlEntry(drvrRefNum);
  219.         if (dceHandle != nil)
  220.             if ((**dceHandle).dCtlFlags & dOpened)
  221.             {
  222.                 /* Driver is open - close it */
  223.                 result = CloseDriver(drvrRefNum);
  224.                 if (result == noErr)
  225.                     /* If driver was closed, ramDisk memory was released! */
  226.                     driverGlobals.ramDisk == nil;
  227.             }
  228.         
  229.         if (driveNum != 0)
  230.         {
  231.             result = RemoveDrive(driveNum, &driveQElPtr);    /* ignore errors */
  232.             if (result == noErr)
  233.                 /* Dispose of the DrvQEl. Since it was allocated as a
  234.                     MyDrvQEl record, we have to subract 4 from the address */
  235.                 DisposePtr((Ptr)((Ptr)(driveQElPtr) - 4));
  236.         }
  237.             
  238.         if (drvrRefNum != 0)
  239.             DriverRemove (drvrRefNum);
  240.         
  241.         if (driverHandle != nil)
  242.         {
  243.             handleState = HGetState(driverHandle);
  244.             if (handleState & 0x20)                /* Is driverHandle a resource? */
  245.                 ReleaseResource(driverHandle);    /* yes, release it */
  246.             else
  247.                 DisposeHandle(driverHandle);    /* no, dispose it */
  248.         }
  249.         
  250.         if (driverGlobals.ramDisk != nil)
  251.             DisposePtr(driverGlobals.ramDisk);
  252.             
  253. #ifdef    __DebugVersion
  254. /* ••• Need to add routine to remove TMON/MacsBug debugging macros */
  255. #endif    __DebugVersion
  256.             
  257.         ShowIcon7(rLoadBadIcon,true);            /* draw bad load icon and move pen */
  258.     }
  259. #ifdef THINK_C
  260.     RestoreA4();
  261. #endif
  262. #ifdef __MWERKS__
  263.     SetA4(oldA4);
  264. #endif
  265. }
  266.  
  267. /*****************************************************************************/
  268.  
  269. /*
  270. **    InitializeGlobals
  271. **
  272. **    Initialize the globals using data read from resources. 
  273. */
  274.  
  275. OSErr    InitializeGlobals (DrvrGlobals *driverGlobals)
  276. {
  277.     OSErr            result = -1;
  278.     Handle            physicalIconHandle, mediaIconHandle;
  279.     ConfigRecHandle    configHandle;
  280.     long            length;
  281.  
  282.     driverGlobals->ramDisk = nil;    /* RAM disk memory isn't allocated yet */
  283.  
  284.     /* Get the user configuration, icons, and the "where" string */
  285.     configHandle = (ConfigRecHandle)Get1Resource ('RDcf', 0);
  286.     physicalIconHandle = Get1Resource('ICN#', rPhysicalIcon);
  287.     mediaIconHandle = Get1Resource('ICN#', rMediaIcon);
  288.     
  289.     if (configHandle && physicalIconHandle && mediaIconHandle)
  290.     {
  291.         /* See if we are supposed to install */
  292.         if ((**configHandle).install)
  293.         {            
  294.             /* Copy the user's preferred volume name to the driver globals. */
  295.             length = (**configHandle).volumeName[0]+1;
  296.             BlockMove((**configHandle).volumeName, driverGlobals->volumeName, length);
  297.             
  298.             /* Copy ICN# to driver globals so it has a physical location icon for volumes. */
  299.             BlockMove( &(**physicalIconHandle), (Ptr)(driverGlobals->physicalIcon), kLargeIconSize);
  300.             
  301.             /* Copy ICN# to driver globals so it has a default media icon for volumes. */
  302.             BlockMove( &(**mediaIconHandle), (Ptr)(driverGlobals->mediaIcon), kLargeIconSize);
  303.             
  304.             /* Put the drive location string into the driver globals. */
  305.             GetIndString(driverGlobals->locationStr, rStringList, rLocationStr);
  306.             if (ResError() != noErr)
  307.                 BlockMove("\pIn RAM", driverGlobals->locationStr, 7);
  308.                         
  309.             driverGlobals->ramSize = (**configHandle).size * 1024;
  310.             
  311.             result = noErr;
  312.         }
  313.     }
  314.     
  315.     if (configHandle)
  316.         ReleaseResource((Handle)configHandle);
  317.     if (physicalIconHandle)
  318.         ReleaseResource(physicalIconHandle);
  319.     if (mediaIconHandle)
  320.         ReleaseResource(mediaIconHandle);
  321.     
  322.     return (result);
  323. }
  324.  
  325. /*****************************************************************************/
  326.  
  327. /*
  328. **    GetUnitTableBase
  329. **    SetUnitTableBase
  330. **    GetUnitEntryCount
  331. **    SetUnitEntryCount
  332. **
  333. **    Functions to encapsulate access to the low-memory globals UTableBase and
  334. **    UnitNtryCnt.
  335. */
  336.  
  337. Ptr        GetUnitTableBase (void)
  338. {
  339.     return (LMGetUTableBase());
  340. }
  341.  
  342. void    SetUnitTableBase (Ptr newUnitTableBase)
  343. {
  344.     LMSetUTableBase(newUnitTableBase);
  345. }
  346.  
  347. #define    UnitNtryCnt    0x01D2
  348.  
  349. short    GetUnitEntryCount (void)
  350. {
  351.     return (*(short *)UnitNtryCnt);
  352. }
  353.  
  354. void    SetUnitEntryCount (short newUnitEntryCount)
  355. {
  356.     *(short *)UnitNtryCnt = newUnitEntryCount;
  357. }
  358.  
  359. /*****************************************************************************/
  360.  
  361. /*
  362. **    GrowUnitTable
  363. **
  364. **    Allocates and switches to a larger unit table.  If the current unit table
  365. **    has less than kMinUnitNum entries, the unit table is increased to
  366. **    kMinUnitNum + 16.  If the current unit table has more than kMinUnitNum
  367. **    entries, the unit table is increased by 4 entries up to kMaxUTEntries.
  368. */
  369.  
  370. OSErr    GrowUnitTable (void)
  371. {
  372.     OSErr    result = noErr;
  373.     Ptr        oldUnitTableBase;
  374.     short    oldUnitEntryCount;
  375.     Ptr        newUnitTableBase;
  376.     short    newUnitEntryCount;
  377.     
  378.     oldUnitTableBase = GetUnitTableBase();
  379.     oldUnitEntryCount = GetUnitEntryCount();
  380.     
  381.     if (oldUnitEntryCount < kMinUnitNum)
  382.         newUnitEntryCount = 64;
  383.     else
  384.         newUnitEntryCount = oldUnitEntryCount + 4;
  385.     
  386.     if (newUnitEntryCount <= kMaxUTEntries)    /* The unit table cannot grow past kMaxUTEntries (128) */
  387.     {
  388.         /* Allocate the new unit table */
  389.         newUnitTableBase = NewPtrSysClear(newUnitEntryCount * sizeof(long));    // mike wiese
  390.         if (newUnitTableBase != nil)
  391.         {
  392.             /*    Copy the old unit table into the new. Although the 
  393.             **    "Driver Education" Tech Note says that you need to disable
  394.             **    interrupts around this operations, you don't. You only need to
  395.             **    perform the steps in the right order because anything that uses
  396.             **    the unit table at interrupt time shouldn't be saving the UTableBase
  397.             **    or UnitNtryCnt values between calls (if they do, they'll break even
  398.             **    if we do disable interrupts around these steps).
  399.             */
  400.         
  401.             /* First, copy the current unit table into the new unit table */
  402.             BlockMove(oldUnitTableBase, newUnitTableBase, oldUnitEntryCount * 4);
  403.         
  404.             /* Now, switch to the new unit table. After this step, the */
  405.             /* Device Manager will be using the new unit table. */
  406.             SetUnitTableBase(newUnitTableBase);
  407.         
  408.             /* Now, tell the system the table is larger. */
  409.             SetUnitEntryCount(newUnitEntryCount);
  410.         
  411.             /* Everything is switched, so we can get rid of the old unit table */
  412.             DisposPtr(oldUnitTableBase);
  413.         }
  414.         else
  415.         {
  416.             Panic("\pGrowUnitTable: New unit table could not be allocated");
  417.             result = unitTblFullErr;
  418.         }
  419.         
  420.     }
  421.     else
  422.     {
  423.         Panic("\pGrowUnitTable: Unit table cannot grow past kMaxUTEntries (128)");
  424.         result = unitTblFullErr;
  425.     }
  426.     
  427.     return (result);
  428. }
  429.  
  430. /*****************************************************************************/
  431.  
  432. /*
  433. **    GetUnusedDrvrRefNum
  434. **
  435. **    Finds the first unused unit table entry >= kMinUnitNum. Returns 0 if no
  436. **    unused entry is found.
  437. */
  438.  
  439. short    GetUnusedDrvrRefNum (void)
  440. {
  441.     DCtlHandle    *unitTable;
  442.     short        unitEntryCount;
  443.     short        unitNumber;
  444.     short        drvrRefNum = 0;    /* default to no entry found */
  445.     
  446.     unitTable = (DCtlHandle *)GetUnitTableBase();
  447.     unitEntryCount = GetUnitEntryCount();
  448.     
  449.     /* Look for the first empty entry */
  450.     unitNumber = kMinUnitNum;
  451.     while ((unitTable[unitNumber] != nil) && (unitNumber < unitEntryCount))
  452.         ++unitNumber;
  453.     
  454.     if (unitTable[unitNumber] == nil)    /* Find an empty entry? */
  455.         /* Yes, then calculate its driver reference number */
  456.         drvrRefNum = -1 * (unitNumber +1);
  457.     
  458.     return (drvrRefNum);
  459. }
  460.  
  461. /*****************************************************************************/
  462.  
  463. /*
  464. **    GetDrvrRefNum
  465. **
  466. **    Gets a reference number for our driver to use.  Grows the unit table if
  467. **    if is less than kMinUnitNum or if there are no empty entries in the
  468. **    unit table.
  469. */
  470.  
  471. OSErr GetDrvrRefNum (short *drvrRefNum)
  472. {
  473.     OSErr    result = noErr;
  474.     
  475.     *drvrRefNum = 0;
  476.     
  477.     /* See if we need to resize before we even look for an empty entry */
  478.     if (GetUnitEntryCount() < kMinUnitNum)
  479.         /* yep, so do it */
  480.         result = GrowUnitTable();
  481.     
  482.     if (result == noErr)
  483.     {
  484.         /* Find an unused driver reference number */
  485.         *drvrRefNum = GetUnusedDrvrRefNum();
  486.         if (*drvrRefNum == 0)
  487.         {
  488.             /* Didn't find one, so try growing the unit table one more time */
  489.             result = GrowUnitTable();
  490.             
  491.             if (result == noErr)
  492.                 /* Find an unused driver reference number */
  493.                 *drvrRefNum = GetUnusedDrvrRefNum();
  494.         }
  495.         if (*drvrRefNum == 0)
  496.             result = unitTblFullErr;
  497.     }
  498.     
  499.     return (result);
  500. }
  501.  
  502. /*****************************************************************************/
  503.  
  504. /*
  505. **    DriverInstall
  506. **
  507. **    Allocate a device control entry low in memory, initialize its dCtlDriver,
  508. **    dCtlFlags, and dCtlRefNum fields, and then add it to the unit table.
  509. */
  510.  
  511. OSErr    DriverInstall (Handle drvrHandle, short drvrRefNum)
  512. {
  513.     OSErr        result = noErr;
  514.     short        unitNum;
  515.     DCtlHandle    *unitTable;
  516.     DCtlHandle    dceHandle;
  517.     
  518.     unitNum = -1 * (drvrRefNum + 1);
  519.     
  520.     unitTable = (DCtlHandle *)GetUnitTableBase();
  521.     
  522.     /* Make room as low as possible because the device control entry will */
  523.     /* be locked while the driver is open */
  524.     ResrvMem(sizeof(DCtlEntry));
  525.     
  526.     dceHandle = (DCtlHandle)NewHandleSysClear(sizeof(DCtlEntry));
  527.     if (dceHandle != nil)
  528.     {
  529.         (**dceHandle).dCtlDriver = (Ptr)drvrHandle;
  530.         (**dceHandle).dCtlFlags = dRAMBased;    /* dRAMBased = dCtlDriver is handle */
  531.         (**dceHandle).dCtlRefNum = drvrRefNum;        
  532.  
  533.         /* Put dceHandle in the unit table */
  534.         unitTable[unitNum] = dceHandle;        
  535.     }
  536.     else
  537.     {
  538.         result = memFullErr;
  539.     }
  540.     
  541.     return (result);
  542. }
  543.  
  544. /*****************************************************************************/
  545.  
  546. /*
  547. **    DriverRemove
  548. **
  549. **    Used to remove a driver. The unit table entry is cleared, the driver
  550. **    handle is disposed, and the device control entry is disposed.
  551. */
  552.  
  553. void    DriverRemove (short drvrRefNum)
  554. {
  555.     short        unitNum;
  556.     DCtlHandle    *unitTable;
  557.     DCtlHandle    dceHandle;
  558.     
  559.     unitNum = -1 * (drvrRefNum + 1);
  560.     unitTable = (DCtlHandle *)GetUnitTableBase();
  561.  
  562.     if (unitNum > 0 && (unitNum <= kMaxUTEntries))
  563.     {
  564.         dceHandle = unitTable[unitNum];
  565.         if (dceHandle != nil)
  566.         {
  567.             /* Make sure the driver isn't open! */
  568.             if (((**dceHandle).dCtlFlags & dOpened) == 0)
  569.             {
  570.                 unitTable[unitNum] = nil;
  571.                 if ((**dceHandle).dCtlDriver != nil)
  572.                     DisposHandle((Handle)(**dceHandle).dCtlDriver);
  573.                     
  574.                 DisposHandle((Handle)dceHandle);                
  575.             }
  576.         }
  577.     }
  578. }
  579.  
  580. /*****************************************************************************/
  581.  
  582. /*
  583. **    AddDriveToQueue
  584. **
  585. **    Find the first unused drive number greater than 4, allocate and initialize
  586. **    a drive queue element (including the drive flags), and add the drive queue
  587. **    element to the drive queue.
  588. */
  589.  
  590. OSErr    AddDriveToQueue (long size, short drvrRef, short *driveNum)
  591. {
  592.     OSErr        result = noErr;
  593.     QHdrPtr        driveQHdr;
  594.     DrvQEl        *drivePtr;
  595.     MyDrvQElPtr    newDrivePtr;
  596.     Boolean        driveNumFound = false;
  597.  
  598.     
  599.     driveQHdr = GetDrvQHdr();
  600.     
  601.     /* find first free drive number */
  602.     *driveNum = 5;                                            /* drive numbers 1-4 are reserved */
  603.     while (! driveNumFound)
  604.     {
  605.         drivePtr = (DrvQEl *)driveQHdr->qHead;                /* get first drive */
  606.         while (drivePtr && *driveNum != drivePtr->dQDrive)    /* order of tests important! */
  607.             drivePtr = (DrvQEl *)drivePtr->qLink;            /* get next drive */
  608.         
  609.         if (drivePtr == nil)
  610.             driveNumFound = true;
  611.         else
  612.             ++(*driveNum);
  613.     }
  614.  
  615.     if (*driveNum > 0)    /* must be a positive short */
  616.     {
  617.         /* allocate new drive queue element */
  618.         newDrivePtr = (MyDrvQElPtr)NewPtrSysClear(sizeof(MyDrvQEl));            
  619.         if (newDrivePtr != nil)
  620.         {
  621.             newDrivePtr->flags        = 0x00080000;            /* non-ejectable, disk not locked */
  622.             newDrivePtr->qType        = 1;                    /* see IM vol.4 p.181 */
  623.             newDrivePtr->dQDrive    = *driveNum;            /* •• dQDrive and dQRefNum are filled */
  624.             newDrivePtr->dQRefNum    = drvrRef;                /* •• in by AddDrive */
  625.             newDrivePtr->dQFSID        = 0;                    /* HFS */
  626.             newDrivePtr->dQDrvSz    = size & 0x0000FFFF;    /* dQDrvSz  = LoWord of size */
  627.             newDrivePtr->dQDrvSz2    = size >> 16;            /* dQDrvSz2 = HiWord of size */
  628.             
  629.             AddDrive (drvrRef, *driveNum, (DrvQEl *)&newDrivePtr->qLink);
  630.         }
  631.         else
  632.             result = memFullErr;
  633.     }
  634.     else
  635.         /* more than 32768 drives!?! */
  636.         result = nsDrvErr;
  637.     
  638.     return (result);
  639. }
  640.  
  641. /*****************************************************************************/
  642.  
  643. /*
  644. **    RemoveDrive
  645. **
  646. **    Find the drive queue element for driveNum in the drive queue and Dequeue it.
  647. **    Return pointer to the drive queue element removed in *drivePtr.
  648. */
  649.  
  650. OSErr    RemoveDrive (short driveNum, DrvQElPtr *drivePtr)
  651. {
  652.     QHdrPtr        driveQHdr;
  653.  
  654.     driveQHdr = GetDrvQHdr();
  655.     *drivePtr = (DrvQEl *)driveQHdr->qHead;                    /* get first drive */
  656.     while (*drivePtr && (driveNum != (*drivePtr)->dQDrive))    /* order of tests important! */
  657.         *drivePtr = (DrvQEl *)(*drivePtr)->qLink;            /* get next drive */
  658.     
  659.     if (*drivePtr != nil)
  660.         return (Dequeue((QElemPtr)*drivePtr, driveQHdr));
  661.     else
  662.         return (nsDrvErr);
  663. }
  664.  
  665. /*****************************************************************************/
  666. /*****************************************************************************/
  667.  
  668. #ifdef    __DebugVersion
  669.  
  670. /*****************************************************************************/
  671.  
  672. short    NumToolboxTraps (void)
  673. {
  674.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap) )
  675.         return (0x200);
  676.     else
  677.         return (0x400);
  678. }
  679.  
  680. /*****************************************************************************/
  681.  
  682. TrapType    GetTrapType (short theTrap)
  683. {
  684.     if (theTrap & 0x0800)
  685.         return (ToolTrap);
  686.     else
  687.         return (OSTrap);
  688. }
  689.  
  690. /*****************************************************************************/
  691.  
  692. Boolean    TrapAvailable (short theTrap)
  693. {
  694.     TrapType    tType;
  695.     
  696.     tType = GetTrapType(theTrap);
  697.     if (tType == ToolTrap)
  698.     {
  699.         theTrap = theTrap & 0x7FF;
  700.         if (theTrap >= NumToolboxTraps() )
  701.             theTrap = _Unimplemented;
  702.     }
  703.     
  704.     return (NGetTrapAddress(theTrap, tType) !=
  705.             NGetTrapAddress(_Unimplemented, ToolTrap) );
  706. }
  707.  
  708. /*****************************************************************************/
  709.  
  710. #define kMacsbugMacroStr    "\p;MC RamDisk 'DM #"
  711. #define kMacsbugMacroStr2    "\p';g"
  712.  
  713. #define kTMONMacroStr        "\p™AddLabel RamDisk,."
  714. #define kTMONMacroStr2        "\p,."
  715.  
  716. #define AddString(src, dst) {    BlockMove(&src[1], dst+i, src[0]); i += src[0]; }
  717.  
  718. /* Add TMON or MacsBug debugger macros for easy viewing of RamDisk */
  719. void    AddDebuggerLabels (DrvrGlobals driverGlobals)
  720. {
  721.     Str255        strbuf = "\p";
  722.     Str31        numstr;
  723.     long        tmonVal;
  724.     short        err;
  725.     Boolean     done = false;
  726.     SignedByte    debugFlags;
  727.     short        i;
  728.  
  729.     if (TrapAvailable(_Gestalt))    /* check for TMON */
  730.     {
  731.         err = Gestalt('TMON',&tmonVal);
  732.         if (err == 0)
  733.         {
  734.             /* Add TMON label */
  735.             i = 1;
  736.             AddString(kTMONMacroStr, strbuf);
  737.             NumToString((long)driverGlobals.ramDisk,numstr);
  738.             AddString(numstr, strbuf);
  739.             AddString(kTMONMacroStr2, strbuf);
  740.             NumToString(driverGlobals.ramSize,numstr);
  741.             AddString(numstr, strbuf);
  742.             strbuf[0] = i - 1;
  743.  
  744.             DebugStr(strbuf);
  745.             
  746.             done = true;
  747.         }
  748.     }
  749.     if (!done)    /* If TMON isn't installed, define a macro for MacsBug */
  750.     {
  751.         debugFlags = *(SignedByte *) 0x0BFF;
  752.         if (debugFlags == -1)
  753.             debugFlags = *(SignedByte *) 0x0120;
  754.         
  755.         if (debugFlags & 0x20)
  756.         {
  757.             /* Define MacsBug macro */
  758.             i = 1;
  759.             
  760.             AddString(kMacsbugMacroStr, strbuf);
  761.             NumToString((long)driverGlobals.ramDisk, numstr);
  762.             AddString(numstr, strbuf);
  763.             AddString(kMacsbugMacroStr2, strbuf);
  764.             strbuf[0] = i - 1;
  765.             
  766.             DebugStr(strbuf);
  767.         }
  768.     }
  769. }
  770.  
  771. /*****************************************************************************/
  772.  
  773. #endif    __DebugVersion
  774.  
  775. /*****************************************************************************/
  776.